package com.exec;

import com.alibaba.fastjson.JSONObject;
import com.tycmc.util.RedisUtil;
import com.util.CommonUtils;
import com.util.DateUtil;
import com.util.DruidUtil;
import com.util.PropertiesUtil;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import ty.pub.TransPacket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by zhangzhuang on 2018/9/13.
 */
public class FenceController {
    /**
     * 计算围栏进出报警
     * @param inputObject
     * @return
     */
    private static double EARTH_RADIUS = 6378.137;
    public static  String execFenceAlarm(com.tycmc.bean.InputObject inputObject){
        //获取设备最新位置工况编号
        String vclkmxcode = PropertiesUtil.getStringPro("VclPstn");
        //信息生成时间编号
        String msgTimeNumber=PropertiesUtil.getStringPro("MsgTimeNumber");
        //#设备围栏信息redis key
        String VclFenceInfo=PropertiesUtil.getStringPro("VclFenceInfo");
        //#设备进出围栏状态redis key
        String VclFenceState=PropertiesUtil.getStringPro("VclFenceState");
        String Fence = PropertiesUtil.getStringPro("Fence");
        //获取kafka拉取到的工况
        TransPacket transPacket = inputObject.getTransPacket();
        //获取基础数据
        Map<String,String> baseInfo = transPacket.getBaseInfoMap();
        //基础时间
        Long baseMsgTime = MapUtils.getLong(baseInfo,msgTimeNumber);
        String msgTime = DateUtil.getStrTime(baseMsgTime,0L);
        //获取设备ID
        String vclId=transPacket.getDeviceId();
        //去掉设备ID的前缀
        vclId=vclId.substring(4,vclId.length());
        //设备围栏基本信息 rediskey
        VclFenceInfo = VclFenceInfo+vclId;
        //设备围栏状态 redis key
        VclFenceState = VclFenceState+vclId;
        //获取工况数据
        Map<String,Map<Long,String>> workStatusMap = transPacket.getWorkStatusMap();
        //用来保存从kafka拉取到的数据
        Map<Long,String> OrgposMap = new HashMap<Long,String>();
        OrgposMap = workStatusMap.get(vclkmxcode);

        List<String> sqlList = new ArrayList<String>();
        //判空
        if(!MapUtils.isEmpty(OrgposMap)){
            //获取信息生成时间数据集合
            Map<String,Object>mapStatic=inputObject.getCacheMap();
            String theVclmsgTime=MapUtils.getString(mapStatic,vclId+"_"+Fence);
            //如果为空，直接存入缓存map中
            if(StringUtils.isBlank(theVclmsgTime)){
                mapStatic.put(vclId+"_"+Fence,DateUtil.getStrTime(baseMsgTime,0));
                sqlList.add(" insert into  CacheKZExecTable(CKZET_VclId,CKZET_LastMsgTime,CKZET_InsertTime,CKZET_Type)values('"+vclId+"','"+msgTime+"',now(),"+Fence+")  " +
                        "ON DUPLICATE KEY UPDATE CKZET_LastMsgTime='"+msgTime+"',CKZET_InsertTime=now()");
            }else{//如果不为空
                //上下时间比较
                long lastVclmsgTime=Long.valueOf(DateUtil.getLongTime(theVclmsgTime));
                if(baseMsgTime>=lastVclmsgTime){
                    mapStatic.put(vclId+"_"+Fence,DateUtil.getStrTime(baseMsgTime,0));
                    sqlList.add(" insert into  CacheKZExecTable(CKZET_VclId,CKZET_LastMsgTime,CKZET_InsertTime,CKZET_Type)values('"+vclId+"','"+msgTime+"',now(),"+Fence+")  " +
                            "ON DUPLICATE KEY UPDATE CKZET_LastMsgTime='"+msgTime+"',CKZET_InsertTime=now()");
                }else{
                    //缓存数据
                    return null;
                }
            }
            Map<Long,String> posMap = new HashMap<Long,String>();
            //可能为多条工况信息，排序并循环处理
            posMap = CommonUtils.sortMapByKey(OrgposMap);
            //读取该条工况值
            //#位置信息{"La":38.3,"Lo":103.25,"Speed":4,"Direction":5,"Satellite":10,"PstnTime":"2017-5-15 10:10:10","gpsIsLast":1}
            for(long timeKey : posMap.keySet()){
                JSONObject jb = JSONObject.parseObject(posMap.get(timeKey));
                //拼接具体时间
                msgTime = jb.getString("PstnTime");
                //获取设备最新位置
                double la = jb.getDoubleValue("La");
                double lo = jb.getDoubleValue("Lo");
                double lastPos[] = new double[]{la,lo};

                //判断redis中是否存在该设备的围栏信息
                if(RedisUtil.exist(VclFenceInfo)){
                    //存在该设备围栏信息/获取该设备的围栏信息
                    Map<String,String> redisFenceInfo = new HashMap<String,String>();
                    redisFenceInfo = RedisUtil.hgetAll(VclFenceInfo);
                    //判断redis中是否存在该设备围栏状态
                    if(RedisUtil.exist(VclFenceState)){
                        //存在，获取该设备redis中的围栏状态
                        Map<String,String> redisFenceState = new HashMap<String,String>();
                        redisFenceState = RedisUtil.hgetAll(VclFenceState);
                        //循环 redisFenceInfo 获取围栏信息
                        for(String fenceInfoId : redisFenceInfo.keySet()){
                            //获取当前围栏基本信息
                            JSONObject fenceInfoJb = JSONObject.parseObject(MapUtils.getString(redisFenceInfo,fenceInfoId));
                            //判断围栏状态中是否存在该围栏信息
                            if(redisFenceState.containsKey(fenceInfoId)){
                                //存在，判断当前设备位置是否在当前围栏内，再与当前状态作比较，有改变则入库，更新redis
                                //获取当前设备对于围栏的状态信息
                                JSONObject fenceStateJb = JSONObject.parseObject(MapUtils.getString(redisFenceState,fenceInfoId));
                                //获取围栏类型(1:圆形，2：矩形)
                                String fenceType = fenceInfoJb.getString("FenceType");
                                if("圆".equals(fenceType)){
                                    //圆形围栏
                                    double cirfencePos[] = new double[]{fenceInfoJb.getDoubleValue("CenterLa"),fenceInfoJb.getDoubleValue("CenterLo")};
                                    double radius = fenceInfoJb.getDoubleValue("Radiu");
                                    String InOutflag = judgecir(lastPos,cirfencePos,radius)?"1":"2";
                                    //获取当前设备对于当前围栏的状态
                                    String redisInOutFlag = fenceStateJb.getString("InOutType");
                                    if(!InOutflag.equals(redisInOutFlag)){
                                        //围栏状态有改变（围栏报警入库，更新redis该围栏状态）
                                        String FltTableN = msgTime.substring(0, 7).replace("-", "");
                                        //新增围栏记录
                                        sqlList.add("INSERT INTO FenceInOutRecord_" + FltTableN + "(FIOR_Vcl_ID,FIOR_InOutType,FIOR_FenceId,FIOR_AlarmTime) VALUES (" + vclId + "," + InOutflag + ","+fenceInfoId+",'" +msgTime+ "')");
                                        //更新redis记录
                                        String updateMsg = "{\"FenId\":\""+fenceInfoId+"\",\"InOutType\":\""+InOutflag+"\",\"VclId\":\""+vclId+"\",\"AlarmTime\":\""+msgTime+"\"}";
                                        RedisUtil.hset(VclFenceState,fenceInfoId,updateMsg);
                                    }
                                }else{
                                    //矩形围栏
                                    double rightup[] = new double[]{fenceInfoJb.getDoubleValue("RightTopLa"),fenceInfoJb.getDoubleValue("RightTopLo")};
                                    double leftdown[] = new double[]{fenceInfoJb.getDoubleValue("LeftbottomLa"),fenceInfoJb.getDoubleValue("LeftbottomLo")};
                                    String InOutflag = judgerec(lastPos,rightup,leftdown)?"1":"2";
                                    //获取当前设备对于当前围栏的状态
                                    String redisInOutFlag = fenceStateJb.getString("InOutType");
                                    if(!InOutflag.equals(redisInOutFlag)){
                                        //围栏状态有改变（围栏报警入库，更新redis该围栏状态）
                                        String FltTableN = msgTime.substring(0, 7).replace("-", "");
                                        //新增围栏记录
                                        sqlList.add("INSERT INTO FenceInOutRecord_" + FltTableN + "(FIOR_Vcl_ID,FIOR_InOutType,FIOR_FenceId,FIOR_AlarmTime) VALUES (" + vclId + "," + InOutflag + ","+fenceInfoId+",'" +msgTime+ "')");
                                        //更新redis记录
                                        String updateMsg = "{\"FenId\":\""+fenceInfoId+"\",\"InOutType\":\""+InOutflag+"\",\"VclId\":\""+vclId+"\",\"AlarmTime\":\""+msgTime+"\"}";
                                        RedisUtil.hset(VclFenceState,fenceInfoId,updateMsg);
                                    }
                                }
                            }else{
                                //不存在，判断当前设备位置是否在当前围栏内
                                //获取围栏类型(1:圆形，2：矩形)
                                String fenceType = fenceInfoJb.getString("FenceType");
                                if("圆".equals(fenceType)){
                                    //圆形围栏
                                    double cirfencePos[] = new double[]{fenceInfoJb.getDoubleValue("CenterLa"),fenceInfoJb.getDoubleValue("CenterLo")};
                                    double radius = fenceInfoJb.getDoubleValue("Radiu");
                                    String InOutflag = judgecir(lastPos,cirfencePos,radius)?"1":"2";
                                    if("1".equals(InOutflag)){
                                        //围栏状态有改变（围栏报警入库，更新redis该围栏状态）
                                        String FltTableN = msgTime.substring(0, 7).replace("-", "");
                                        //新增围栏记录
                                        sqlList.add("INSERT INTO FenceInOutRecord_" + FltTableN + "(FIOR_Vcl_ID,FIOR_InOutType,FIOR_FenceId,FIOR_AlarmTime) VALUES (" + vclId + "," + InOutflag + ","+fenceInfoId+",'" +msgTime+ "')");
                                        //更新redis记录
                                        String updateMsg = "{\"FenId\":\""+fenceInfoId+"\",\"InOutType\":\""+InOutflag+"\",\"VclId\":\""+vclId+"\",\"AlarmTime\":\""+msgTime+"\"}";
                                        RedisUtil.hset(VclFenceState,fenceInfoId,updateMsg);
                                    }
                                }else{
                                    //矩形围栏
                                    double rightup[] = new double[]{fenceInfoJb.getDoubleValue("RightTopLa"),fenceInfoJb.getDoubleValue("RightTopLo")};
                                    double leftdown[] = new double[]{fenceInfoJb.getDoubleValue("LeftbottomLa"),fenceInfoJb.getDoubleValue("LeftbottomLo")};
                                    String InOutflag = judgerec(lastPos,rightup,leftdown)?"1":"2";
                                    if("1".equals(InOutflag)){
                                        //围栏状态有改变（围栏报警入库，更新redis该围栏状态）
                                        String FltTableN = msgTime.substring(0, 7).replace("-", "");
                                        //新增围栏记录
                                        sqlList.add("INSERT INTO FenceInOutRecord_" + FltTableN + "(FIOR_Vcl_ID,FIOR_InOutType,FIOR_FenceId,FIOR_AlarmTime) VALUES (" + vclId + "," + InOutflag + ","+fenceInfoId+",'" +msgTime+ "')");
                                        //更新redis记录
                                        String updateMsg = "{\"FenId\":\""+fenceInfoId+"\",\"InOutType\":\""+InOutflag+"\",\"VclId\":\""+vclId+"\",\"AlarmTime\":\""+msgTime+"\"}";
                                        RedisUtil.hset(VclFenceState,fenceInfoId,updateMsg);
                                    }
                                }
                            }
                        }
                    }else{
                        //当前该设备尚未在redis中有围栏状态信息（根据当前设备位置判断设备是否在某一个围栏内）
                        //循环 redisFenceInfo 获取围栏信息
                        for(String fenceInfoId : redisFenceInfo.keySet()){
                            //获取当前围栏基本信息
                            JSONObject fenceInfoJb = JSONObject.parseObject(MapUtils.getString(redisFenceInfo,fenceInfoId));
                            //获取围栏类型(1:圆形，2：矩形)
                            String fenceType = fenceInfoJb.getString("FenceType");
                            if("圆".equals(fenceType)){
                                //圆形围栏
                                double cirfencePos[] = new double[]{fenceInfoJb.getDoubleValue("CenterLa"),fenceInfoJb.getDoubleValue("CenterLo")};
                                double radius = fenceInfoJb.getDoubleValue("Radiu");
                                String InOutflag = judgecir(lastPos,cirfencePos,radius)?"1":"2";
                                if("1".equals(InOutflag)){
                                    //围栏状态有改变（围栏报警入库，更新redis该围栏状态）
                                    String FltTableN = msgTime.substring(0, 7).replace("-", "");
                                    //新增围栏记录
                                    sqlList.add("INSERT INTO FenceInOutRecord_" + FltTableN + "(FIOR_Vcl_ID,FIOR_InOutType,FIOR_FenceId,FIOR_AlarmTime) VALUES (" + vclId + "," + InOutflag + ","+fenceInfoId+",'" +msgTime+ "')");
                                    //更新redis记录
                                    String updateMsg = "{\"FenId\":\""+fenceInfoId+"\",\"InOutType\":\""+InOutflag+"\",\"VclId\":\""+vclId+"\",\"AlarmTime\":\""+msgTime+"\"}";
                                    RedisUtil.hset(VclFenceState,fenceInfoId,updateMsg);
                                }
                            }else{
                                //矩形围栏
                                double rightup[] = new double[]{fenceInfoJb.getDoubleValue("RightTopLa"),fenceInfoJb.getDoubleValue("RightTopLo")};
                                double leftdown[] = new double[]{fenceInfoJb.getDoubleValue("LeftbottomLa"),fenceInfoJb.getDoubleValue("LeftbottomLo")};
                                String InOutflag = judgerec(lastPos,rightup,leftdown)?"1":"2";
                                if("1".equals(InOutflag)){
                                    //围栏状态有改变（围栏报警入库，更新redis该围栏状态）
                                    String FltTableN = msgTime.substring(0, 7).replace("-", "");
                                    //新增围栏记录
                                    sqlList.add("INSERT INTO FenceInOutRecord_" + FltTableN + "(FIOR_Vcl_ID,FIOR_InOutType,FIOR_FenceId,FIOR_AlarmTime) VALUES (" + vclId + "," + InOutflag + ","+fenceInfoId+",'" +msgTime+ "')");
                                    //更新redis记录
                                    String updateMsg = "{\"FenId\":\""+fenceInfoId+"\",\"InOutType\":\""+InOutflag+"\",\"VclId\":\""+vclId+"\",\"AlarmTime\":\""+msgTime+"\"}";
                                    RedisUtil.hset(VclFenceState,fenceInfoId,updateMsg);
                                }
                            }
                        }
                    }
                }
            }
            if(sqlList.size()!=0){
                DruidUtil.batch(sqlList);
            }
        }

        return null;
    }
    //判断当前位置点是否在圆形围栏中
    public static boolean judgecir(double[] posMap,double[] cirfence,double radius){
        double distance = getDistance(posMap[0], posMap[1], cirfence[0], cirfence[1]);
        System.out.println(distance);
        double r = radius/1000;
        System.out.println(r);
        if (distance > r) {
            return false;
        } else {
            return true;
        }
    }

    //判断当前位置点是否在矩形围栏中
    public static boolean judgerec(double pos[],double rightup[],double leftdown[]){
        if(pos[1]<rightup[1] && pos[1]>leftdown[1]){
            if(pos[0]<rightup[0] && pos[0]>leftdown[0]){
                return true;
            }
        }
        return false;
    }

    public static double getDistance(double lat1, double lng1, double lat2,double lng2){
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lng1) - rad(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
                Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000d) / 10000d;
        return s;
    }
    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }
}
